home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / snip9707.zip / CPUID.ASM < prev    next >
Assembly Source File  |  1997-07-05  |  13KB  |  306 lines

  1. ;  +++Date last modified: 05-Jul-1997
  2.  
  3. ; cpuid.asm
  4. ;
  5. ; This module contains a C callable routine which returns a 16-bit
  6. ; integer (in AX) which indicates the type of CPU on which the
  7. ; program is running.  The low eight bits (AL) contain a number
  8. ; corresponding to the family number (e.g. 0 = 8086, 1 = 80186,
  9. ; 2 = 80286, etc.).  The high eight bits (AH) contain a collection
  10. ; of bit flags which are defined below.
  11. ;
  12. ;       written on Thu  10-31-1996  by Edward J. Beroset
  13. ;               and released to the public domain by the author
  14. ;
  15. %       .MODEL  memodel,C               ;Add model support via command
  16.                                         ;line macros, e.g.
  17.                                         ;MASM /Dmemodel=LARGE,
  18.                                         ;TASM /Dmemodel=SMALL, etc.
  19.  
  20.         .8086
  21.         PUBLIC cpu_id
  22.  
  23. ;
  24. ; using MASM 6.11       Ml /c /Fl CPUID.ASM
  25. ;
  26. ; using TASM 4.00       TASM CPUID.ASM
  27. ;
  28. ; using older assemblers, you may have to use the following equate
  29. ; and eliminate the .586 directive
  30. ;
  31. ;CPUID equ "dw 0a20fh"
  32. ;
  33. ; bit flags for high eight bits of return value
  34. ;
  35. HAS_NPU         equ     01h
  36. IS386_287       equ     02h
  37. IS386SX         equ     04h
  38. CYRIX           equ     08h
  39. NEC             equ     10h
  40. NEXGEN          equ     20h
  41. AMD             equ     40h
  42. UMC             equ     80h
  43.  
  44.         .code
  45.  
  46. cpu_id  proc
  47.         push    bx
  48.         push    cx
  49.         push    dx
  50.         push    bp
  51.         mov     bp,sp
  52.         xor     dx,dx                   ; result = 0 (UNKNOWN)
  53. ;**********************************************************************
  54. ; The Cyrix test
  55. ;
  56. ;   Cyrix processors do not alter the AF (Aux carry) bit when
  57. ;   executing an XOR.  Intel CPUs (and, I think, all the others)
  58. ;   clear the AF flag while executing an XOR AL,AL.
  59. ;
  60. ;**********************************************************************
  61. TestCyrix:
  62.         mov     al,0fh                  ;
  63.         aas                             ; set AF flag
  64.         xor     al,al                   ; only Cyrix leaves AF set
  65.         aas                             ;
  66.         jnc     Test8086                ;
  67.         or      dh,CYRIX                ; it's at least an 80386 clone
  68.         jmp     Test486                 ;
  69. ;**********************************************************************
  70. ;
  71. ; The 80186 or under test
  72. ;
  73. ;   On <80286 CPUs, the SP register was decremented *before* being
  74. ;   pushed onto the stack.  All later CPUs do it correctly.
  75. ;**********************************************************************
  76. Test8086:
  77.         push    sp                      ; Q: is it an 8086, 80188, or
  78.         pop     ax                      ;
  79.         cmp     ax,bp                   ;
  80.         je      Test286                 ;   N: it's at least a 286
  81. ;**********************************************************************
  82. ; The V20/V30 test
  83. ;
  84. ;   NEC's CPUs set the state of ZF (the Zero flag) correctly after
  85. ;   a MUL.  Intel's CPUs do not -- officially the state of ZF is
  86. ;   "undefined" after a MUL or IMUL.
  87. ;
  88. ;**********************************************************************
  89. TestV20:
  90.         xor     al,al                   ; clear the zero flag
  91.         mov     al,1                    ;
  92.         mul     al                      ;
  93.         jnz     Test186                 ;
  94.         or      dh,NEC                  ; it's a V20 or a V30
  95. ;**********************************************************************
  96. ; The 80186 test
  97. ;
  98. ;   On the 80186, shifts only use the five least significant bits,
  99. ;   while the 8086 uses all 8, so a request to shift 32 bits will
  100. ;   be requested as a shift of zero bits on the 80186.
  101. ;
  102. ;**********************************************************************
  103. Test186:
  104.         mov     al,01h                  ;
  105.         mov     cl,32                   ; shift right by 33 bits
  106.         shr     al,cl                   ;
  107.         mov     dl,al                   ; al = 0 for 86, al = 1 for 186
  108. longTestNpu:
  109.         jmp     TestNpu                 ;
  110.  
  111. ;**********************************************************************
  112. ; The 286 test
  113. ;   Bits 12-15 (the top four) of the flags register are all set to
  114. ;   0's on a 286 and can't be set to 1's.
  115. ;
  116. ;**********************************************************************
  117. Test286:
  118.         .286
  119.         mov     dl,2                    ; it's at least a 286
  120.         pushf                           ; save the flags
  121.         pop     ax                      ; fetch 'em into AX
  122.         or      ah,0f0h                 ; try setting those high bits
  123.         push    ax                      ;
  124.         popf                            ; run it through the flags reg
  125.         pushf                           ;
  126.         pop     ax                      ; now check the results
  127.         and     ah,0F0h                 ; Q: are bits clear?
  128.         jz      longTestNpu             ;   Y: it's a 286
  129.  
  130. ;**********************************************************************
  131. ; The 386 test
  132. ;
  133. ;   The AC (Alignment Check) bit was introduced on the 486.  This
  134. ;   bit can't be toggled on the 386.
  135. ;
  136. ;**********************************************************************
  137. Test386:
  138.         .386
  139.         mov     dl,3                    ; it's at least a 386
  140.         pushfd                          ; assure enough stack space
  141.         cli
  142.         and     sp, NOT 3               ; align stack to avoid AC fault
  143.         pushfd                          ;
  144.         pop     cx                      ;
  145.         pop     ax                      ;
  146.         mov     bx,ax                   ; save a copy
  147.         xor     al,4                    ; flip AC bit
  148.         push    ax                      ;
  149.         push    cx                      ;
  150.         popfd                           ;
  151.         pushfd                          ;
  152.         pop     cx                      ;
  153.         pop     ax                      ;
  154.         and     al,4                    ;
  155.         sti
  156.         xor     al,bl                   ; Q: did AC bit change?
  157.         jnz     Test486                 ;   N: it's a 386
  158.         .386P
  159. ;**********************************************************************
  160. ; The 386SX test
  161. ;
  162. ;   On the 386SX, the ET (Extension Type) bit of CR0 is permanently
  163. ;   set to 1 and can't be toggled.  On the 386DX this bit can be
  164. ;   cleared.
  165. ;**********************************************************************
  166.         mov     eax,cr0
  167.         mov     bl,al                   ; save correct value
  168.         and     al,not 10h              ; try clearing ET bit
  169.         mov     cr0,eax                 ;
  170.         mov     eax,cr0                 ; read back ET bit
  171.         xchg    bl,al                   ; patch in the correct value
  172.         mov     cr0,eax                 ;
  173.         test    bl,10h                  ; Q: was bit cleared?
  174.         jz      TestNpu                 ;  Y: it's a DX
  175.         or      dh,IS386SX              ;  N: it's probably an SX
  176.  
  177. ;**********************************************************************
  178. ; The 486 test
  179. ;
  180. ;   Try toggling the ID bit in EFLAGS.  If the flag can't be toggled,
  181. ;   it's a 486.
  182. ;
  183. ; Note:
  184. ;   This one isn't completely reliable -- I've heard that the NexGen
  185. ;   CPU's don't make it through this one even though they have all
  186. ;   the Pentium instructions.
  187. ;**********************************************************************
  188. Test486:
  189.         .486
  190.         pushfd
  191.         pop     cx
  192.         pop     bx
  193.         mov     dl,4                    ;
  194.         mov     ax,bx                   ;
  195.         xor     al,20h                  ; flip EFLAGS ID bit
  196.         push    ax                      ;
  197.         push    cx                      ;
  198.         popfd                           ;
  199.         pushfd                          ;
  200.         pop     cx                      ;
  201.         pop     ax                      ;
  202.         and     al,20h                  ; check ID bit
  203.         xor     al,bl                   ; Q: did ID bit change?
  204.         jz      TestNpu                 ;   N: it's a 486
  205.  
  206. ;**********************************************************************
  207. ; The Pentium+ tests
  208. ;
  209. ;   First, we issue a CPUID instruction with EAX=0 to get back the
  210. ;   manufacturer's name string.  (We only check the first letter.)
  211. ;
  212. ;**********************************************************************
  213. PentPlus:
  214.         .586
  215.         push    dx                      ;
  216.         xor     eax,eax                 ;
  217.         cpuid                           ;
  218.         pop     dx                      ;
  219.         cmp     bl,'G'                  ; Q: GenuineIntel?
  220.         jz      WhatPent                ;   Y: what kind?
  221.         or      dh,CYRIX                ; assume Cyrix for now
  222.         cmp     bl,'C'                  ;
  223.         jz      WhatPent                ;
  224.         xor     dh,(CYRIX OR AMD)       ;
  225.         cmp     bl,'A'                  ;
  226.         jz      WhatPent                ;
  227.         xor     dh,(AMD OR NEXGEN)      ;
  228.         cmp     bl,'N'                  ;
  229.         jz      WhatPent                ;
  230.         xor     dh,(NEXGEN OR UMC)      ; assume it's UMC
  231.         cmp     bl,'U'                  ;
  232.         jz      WhatPent                ;
  233.         xor     dh,UMC                  ; we don't know who made it!
  234. ;**********************************************************************
  235. ; The Pentium+ tests (part II)
  236. ;
  237. ;   This test simply gets the family information via the CPUID
  238. ;   instruction
  239. ;
  240. ;**********************************************************************
  241. WhatPent:
  242.         push    edx                     ;
  243.         xor     eax,eax                 ;
  244.         inc     al                      ;
  245.         cpuid                           ;
  246.         pop     edx                     ;
  247.         and     ah,0fh                  ;
  248.         mov     dl,ah                   ; put family code in DL
  249.  
  250. ;**********************************************************************
  251. ; The NPU test
  252. ;
  253. ;   We reset the NPU (using the non-wait versions of the instruction, of
  254. ;   course!), put a non-zero value on the stack, then write the NPU
  255. ;   status word to that stack location.  Then we check for zero, which
  256. ;   is what would be there if there were an NPU.
  257. ;
  258. ;**********************************************************************
  259. TestNpu:
  260.         .8087
  261.         .8086
  262.         mov     sp,bp                   ; restore stack
  263.         fninit                          ; init but don't wait
  264.         mov     ax,0EdEdh               ;
  265.         push    ax                      ; put non-zero value on stack
  266.         fnstsw  word ptr [bp-2]         ; save NPU status word
  267.         pop     ax                      ;
  268.         or      ax,ax                   ; Q: was status = 0?
  269.         jnz     finish                  ;   N: no NPu
  270.         or      dh,HAS_NPU              ;   Y: has NPU
  271.  
  272. ;**********************************************************************
  273. ; The 386/287 combo test
  274. ;
  275. ;   Since the 386 can be paired with either a 387 or 287, we check to
  276. ;   see if the NPU believes that +infinity equals -infinity.  The 387
  277. ;   says they're equal, while the 287 doesn't.
  278. ;
  279. ;**********************************************************************
  280.         cmp     dl,3                    ; Q: is CPU a 386?
  281.         jnz     finish                  ;  N: no need to check infinities
  282.         fld1                            ; load 1
  283.         fldz                            ; load 0
  284.         fdiv                            ; calculate infinity! (1/0)
  285.         fld     st                      ; duplicate it
  286.         fchs                            ; change signs of top inf
  287.         fcompp                          ; identical?
  288.         push    ax                      ;
  289.         fstsw   word ptr [bp-2]         ;
  290.         pop     ax                      ;
  291.         test    ah,40h                  ; Q: does NPU say they're equal?
  292.         jz      finish                  ;  N: it's a 387
  293.         or      dh,IS386_287            ;
  294. finish:
  295.         mov     ax,dx                   ; put our return value in place
  296.         pop     bp                      ; clean up stack
  297.         pop     dx                      ;
  298.         pop     cx                      ;
  299.         pop     bx                      ;
  300.  
  301.         ret                             ;
  302. cpu_id  endp
  303.  
  304.         END
  305.